Skip to content

Conversation

@MartinJM
Copy link

This PR adds support for the Korad KA3005PS. Protocol is almost the same as for the KA3005P, except that it needs a newline1 at the end of every request, and sends back a newline at the end of every response. That is added in this PR.

One thing to keep in mind: This PR also sends the newline for the *IDN? to identify the device. I assume this will also work for the KA3005P, but I cannot check.

Footnotes

  1. It also seems to work with a carriage return, but the responses will still end with a newline. I've implemented it with newlines.

@cnf
Copy link

cnf commented May 25, 2025

I think this is the same as the velleman LABPS3005DN needs i'll try and check somewhere this week on mine

@cnf
Copy link

cnf commented May 26, 2025

That doesn't work.
I don't know if this is the right place. but attached is the .patch file i got it to detect my Velleman with, but it doesn't operate well.

LABPS3005DN.txt
it seems the LABPS3005DN expects an actual '\n' as a string.

@MartinJM
Copy link
Author

I'm not sure where you applied that patch? For this PR you'd need to add the KORAD_QUIRK_NEWLINE for your model to enable the newline sending/stripping.

I also see a change of OUT[01] to OUTPUT[01], which would break on other models.

@cnf
Copy link

cnf commented May 26, 2025

I'm not sure where you applied that patch? For this PR you'd need to add the KORAD_QUIRK_NEWLINE for your model to enable the newline sending/stripping.

I also see a change of OUT[01] to OUTPUT[01], which would break on other models.

Right, I took your patch, and added

+	{"Velleman", "LABPS3005DN", "QJE3005PV1.0", 1, volts_30, amps_5,
+        KORAD_QUIRK_ID_OPT_VERSION|KORAD_QUIRK_NEWLINE},

which did not detect my velleman.

My patch I uploaded lets me detect my velleman, but does not get me to a functioning state.

https://cdn.velleman.eu/downloads/80/labps3005dn_communication_protocol.pdf is the doc for my velleman btw.

I was just hopeful your patch would work for my device, because you mentioned it needed the newlines, I'm sorry if I am highjacking the thread...

@MartinJM MartinJM force-pushed the add_device_korad_ka3005ps branch from cf8934c to c79a973 Compare May 26, 2025 18:29
@MartinJM
Copy link
Author

MartinJM commented May 26, 2025

It does look fairly close - the only real differences seem to be the OUTPUT request and the STATUS response.

I was just hopeful your patch would work for my device, because you mentioned it needed the newlines, I'm sorry if I am highjacking the thread...

No worries! I have changed the code a bit to see if it will allow your device to connect properly as well. If it doesn't take too much work it'd be nice to add support for it as well!

You'll need to apply something like the following patch for your device though:

diff --git a/src/hardware/korad-kaxxxxp/api.c b/src/hardware/korad-kaxxxxp/api.c
index c6b9b1f6..583252a3 100644
--- a/src/hardware/korad-kaxxxxp/api.c
+++ b/src/hardware/korad-kaxxxxp/api.c
@@ -76,6 +76,8 @@ static const struct korad_kaxxxxp_model models[] = {
        {"Tenma", "72-2710", "", 1, volts_30, amps_5, 0},
        {"Velleman", "LABPS3005D", "", 1, volts_30, amps_5,
                KORAD_QUIRK_LABPS_OVP_EN},
+       {"Velleman", "LABPS3005DN", "", 1, volts_30, amps_5,
+               KORAD_QUIRK_VELLEMAN | KORAD_QUIRK_NEWLINE},
        {"Velleman", "PS3005D V1.3", "VELLEMANPS3005DV1.3" , 1, volts_30, amps_5,
                KORAD_QUIRK_ID_TRAILING | KORAD_QUIRK_SLOW_PROCESSING},
        {"Velleman", "PS3005D", "", 1, volts_30, amps_5, 0},
diff --git a/src/hardware/korad-kaxxxxp/protocol.c b/src/hardware/korad-kaxxxxp/protocol.c
index 0ce7206e..b27d8f9c 100644
--- a/src/hardware/korad-kaxxxxp/protocol.c
+++ b/src/hardware/korad-kaxxxxp/protocol.c
@@ -229,8 +229,13 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
                        "VSET1:%05.2f", devc->set_voltage_target);
                break;
        case KAXXXXP_OUTPUT:
-               sr_snprintf_ascii(msg, sizeof(msg),
-                       "OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+               if (devc->model->quirks & KORAD_QUIRK_VELLEMAN) {
+                       sr_snprintf_ascii(msg, sizeof(msg),
+                               "OUTPUT%1d", (devc->set_output_enabled) ? 1 : 0);
+               } else {
+                       sr_snprintf_ascii(msg, sizeof(msg),
+                               "OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+               }
                /* Set value back to recognize changes */
                devc->output_enabled = devc->set_output_enabled;
                break;
diff --git a/src/hardware/korad-kaxxxxp/protocol.h b/src/hardware/korad-kaxxxxp/protocol.h
index 43653d14..19aef882 100644
--- a/src/hardware/korad-kaxxxxp/protocol.h
+++ b/src/hardware/korad-kaxxxxp/protocol.h
@@ -40,7 +40,8 @@ enum korad_quirks_flag {
        KORAD_QUIRK_ID_OPT_VERSION = 1UL << 3,
        KORAD_QUIRK_SLOW_PROCESSING = 1UL << 4,
        KORAD_QUIRK_NEWLINE = 1UL << 5,
-       KORAD_QUIRK_ALL = (1UL << 6) - 1,
+       KORAD_QUIRK_VELLEMAN = 1UL << 6,
+       KORAD_QUIRK_ALL = (1UL << 7) - 1,
 };
 
 /* Information on single model */

The STATUS response is probably not parsed properly though.

@cnf
Copy link

cnf commented May 27, 2025

Im probably doing something weird, but I am faling at applying your patch for my velleman ^^;

error: builder for '/nix/store/vxbwd5bik9h9vir6s196v8yp25h27bnb-libsigrok-0.5.2-unstable-2024-10-20.drv' failed with exit code 1;
        last 14 log lines:
        > Running phase: unpackPhase
        > unpacking source archive /nix/store/xcxgsps2nbp1ny2ksw0gpcs6171hqycq-libsigrok-c79a973
        > source root is libsigrok-c79a973
        > Running phase: patchPhase
        > applying patch /nix/store/vfl9vlhwsm52yxd3pripz6g9ic7fcn8y-VELLEMAN.patch
        > patching file src/hardware/korad-kaxxxxp/api.c
        > Hunk #1 FAILED at 76.
        > 1 out of 1 hunk FAILED -- saving rejects to file src/hardware/korad-kaxxxxp/api.c.rej
        > patching file src/hardware/korad-kaxxxxp/protocol.c
        > Hunk #1 FAILED at 229.
        > 1 out of 1 hunk FAILED -- saving rejects to file src/hardware/korad-kaxxxxp/protocol.c.rej
        > patching file src/hardware/korad-kaxxxxp/protocol.h
        > Hunk #1 FAILED at 40.
        > 1 out of 1 hunk FAILED -- saving rejects to file src/hardware/korad-kaxxxxp/protocol.h.rej
        For full logs, run 'nix log /nix/store/vxbwd5bik9h9vir6s196v8yp25h27bnb-libsigrok-0.5.2-unstable-2024-10-20.drv'.

I'll have another poke later on, my brain is a bit foggy atm i'm afraid.

@MartinJM
Copy link
Author

You'll need to apply it on top of this PR. I think you tried to apply it on master right?

I also forgot to add the newline quirk for your device - just edited it in, so you might need to grab it again.

@cnf
Copy link

cnf commented May 27, 2025

i first tried master, then this PR as a patch, then the other one.
then i tried the hash from this PR, and the new patch, both gave that error

final: prev: 
{
  libsigrok = prev.libsigrok.overrideAttrs (prevAttrs: {
    buildInputs = (prevAttrs.buildInputs or []) ++ [prev.nettle];
      src = prev.fetchgit {
        #url = "git://sigrok.org/libsigrok";
        url = "https://github.com/sigrokproject/libsigrok/";
        rev = "c79a9738f8643fe84998d95d0578ec1035235471";
        hash = "sha256-Ogg7/8ZIqKejyp9HWLRa6DMWM7nxGgVMew+EbaNxCKo=";
      };
    patches = (prevAttrs.patches or []) ++ [
      #../patches/269.patch
      ../patches/VELLEMAN.patch
    ];
  });
}

I don;t know if you are familiar with nix, but that is the last one i tried.

@MartinJM
Copy link
Author

Ah I think something went wrong with my patch. I recreated it and double-checked this one, so it should work:

diff --git a/src/hardware/korad-kaxxxxp/api.c b/src/hardware/korad-kaxxxxp/api.c
index c6b9b1f6..3967a0fb 100644
--- a/src/hardware/korad-kaxxxxp/api.c
+++ b/src/hardware/korad-kaxxxxp/api.c
@@ -76,6 +76,8 @@ static const struct korad_kaxxxxp_model models[] = {
 	{"Tenma", "72-2710", "", 1, volts_30, amps_5, 0},
 	{"Velleman", "LABPS3005D", "", 1, volts_30, amps_5,
 		KORAD_QUIRK_LABPS_OVP_EN},
+	{"Velleman", "LABPS3005DN", "", 1, volts_30, amps_5,
+		KORAD_QUIRK_NEWLINE | KORAD_QUIRK_VELLEMAN},
 	{"Velleman", "PS3005D V1.3", "VELLEMANPS3005DV1.3" , 1, volts_30, amps_5,
 		KORAD_QUIRK_ID_TRAILING | KORAD_QUIRK_SLOW_PROCESSING},
 	{"Velleman", "PS3005D", "", 1, volts_30, amps_5, 0},
diff --git a/src/hardware/korad-kaxxxxp/protocol.c b/src/hardware/korad-kaxxxxp/protocol.c
index 0ce7206e..b27d8f9c 100644
--- a/src/hardware/korad-kaxxxxp/protocol.c
+++ b/src/hardware/korad-kaxxxxp/protocol.c
@@ -229,8 +229,13 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
 			"VSET1:%05.2f", devc->set_voltage_target);
 		break;
 	case KAXXXXP_OUTPUT:
-		sr_snprintf_ascii(msg, sizeof(msg),
-			"OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		if (devc->model->quirks & KORAD_QUIRK_VELLEMAN) {
+			sr_snprintf_ascii(msg, sizeof(msg),
+				"OUTPUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		} else {
+			sr_snprintf_ascii(msg, sizeof(msg),
+				"OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		}
 		/* Set value back to recognize changes */
 		devc->output_enabled = devc->set_output_enabled;
 		break;
diff --git a/src/hardware/korad-kaxxxxp/protocol.h b/src/hardware/korad-kaxxxxp/protocol.h
index 43653d14..19aef882 100644
--- a/src/hardware/korad-kaxxxxp/protocol.h
+++ b/src/hardware/korad-kaxxxxp/protocol.h
@@ -40,7 +40,8 @@ enum korad_quirks_flag {
 	KORAD_QUIRK_ID_OPT_VERSION = 1UL << 3,
 	KORAD_QUIRK_SLOW_PROCESSING = 1UL << 4,
 	KORAD_QUIRK_NEWLINE = 1UL << 5,
-	KORAD_QUIRK_ALL = (1UL << 6) - 1,
+	KORAD_QUIRK_VELLEMAN = 1UL << 6,
+	KORAD_QUIRK_ALL = (1UL << 7) - 1,
 };
 
 /* Information on single model */

@cnf
Copy link

cnf commented May 27, 2025

hmm, not sure what I am doing wrong:

sr: [00:00.014127] hwdriver: sr_config_list(): key 2147418112 (NULL) sdi (nil) cg NULL -> [uint32 20000, 20001, 20003]
sr: [00:00.014149] serial: Opening serial port '/dev/ttyUSB0' (flags 1).
sr: [00:00.015854] serial: Parsing parameters from "9600/8n1".
sr: [00:00.015946] serial: Got params: rate 9600, frame 8/0/1, flow 0, rts -1, dtr -1.
sr: [00:00.015962] serial: Setting serial parameters on port /dev/ttyUSB0.
sr: [00:00.016191] serial: DBG: serial_set_params() rate 9600, 8n1
sr: [00:00.016205] serial: Flushing serial port /dev/ttyUSB0.
sr: [00:00.016227] korad-kaxxxxp: Want max 48 bytes.
sr: [00:00.016245] korad-kaxxxxp: Sending '*IDN?'.
sr: [00:00.016283] serial: Wrote 6/6 bytes.
sr: [00:00.016651] korad-kaxxxxp: want 48 bytes, timeout/retry: init 60/100, later 13/1.
sr: [00:06.030752] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:06.030806] korad-kaxxxxp: Received: 0, 
sr: [00:06.030845] korad-kaxxxxp: Unsupported model ID '', aborting.
sr: [00:06.030882] hwdriver: Scan found 0 devices (korad-kaxxxxp).
No devices found.

@cnf
Copy link

cnf commented May 27, 2025

little bit more info:

± sigrok-cli -d korad-kaxxxxp:conn=/dev/ttyUSB0:force_detect=QJE3005PV1.0 -l 5 --show
sr: [00:00.000060] log: libsigrok loglevel set to 5.
sr: [00:00.000099] backend: libsigrok 0.6.0/4:0:0.
sr: [00:00.000261] backend: Libs: glib 2.82.5 (rt: 2.82.5/8205:5), zlib 1.3.1, libzip 1.11.3, minilzo 2.10, libserialport 0.1.1/1:0:1 (rt: 0.1.1/1:0:1), libusb-1.0 1.0.27.11882 API 0x0100010a, hidapi 0.14.0, bluez 5.79, libftdi 1.5.
sr: [00:00.000333] backend: Host: x86_64-pc-linux-gnu, little-endian.
sr: [00:00.000379] backend: SCPI backends: TCP, serial, USBTMC.
sr: [00:00.000422] backend: Firmware search paths:
sr: [00:00.000538] backend:  - /home/cnf/.local/share/sigrok-firmware
sr: [00:00.000573] backend:  - /nix/store/6xmixr2x5h9bqifb4zf4hv3y3m8f5mlf-libsigrok-0.5.2-unstable-2024-10-20/share/sigrok-firmware
sr: [00:00.000614] backend:  - /nix/store/rhphinzabvbbb65d1qdjayhb0fx4q2kj-network-manager-applet-1.36.0/share/sigrok-firmware
sr: [00:00.000670] backend:  - /nix/store/ciigf79sbx1pckyyjzzv9nrny96lrijf-gnome-mimeapps/share/sigrok-firmware
sr: [00:00.000698] backend:  - /nix/store/m3cndj0jvn72ri17pmd6yz83d582186r-desktops/share/sigrok-firmware
sr: [00:00.000725] backend:  - /home/cnf/.nix-profile/share/sigrok-firmware
sr: [00:00.000752] backend:  - /nix/profile/share/sigrok-firmware
sr: [00:00.000779] backend:  - /home/cnf/.local/state/nix/profile/share/sigrok-firmware
sr: [00:00.000805] backend:  - /etc/profiles/per-user/cnf/share/sigrok-firmware
sr: [00:00.000833] backend:  - /nix/var/nix/profiles/default/share/sigrok-firmware
sr: [00:00.000868] backend:  - /run/current-system/sw/share/sigrok-firmware
sr: [00:00.000933] backend:  - /nix/store/ibzdvd08vnfzihyq9k4h9c3m2ghi5sp2-gnome-shell-47.2/share/gsettings-schemas/gnome-shell-47.2/sigrok-firmware
sr: [00:00.000988] backend:  - /nix/store/57kcdgar0vnchc9f2049hlwj9cjl4p3s-gnome-shell-extensions-47.2/share/gsettings-schemas/gnome-shell-extensions-47.2/sigrok-firmware
sr: [00:00.001137] backend: Sanity-checking all drivers.
sr: [00:00.001214] backend: Sanity-checking all input modules.
sr: [00:00.001289] backend: Sanity-checking all output modules.
sr: [00:00.001363] backend: Sanity-checking all transform modules.
srd: libsigrokdecode loglevel set to 5.
Driver functions:
    Power supply
sr: [00:00.044541] hwdriver: sr_config_list(): key 2147418112 (NULL) sdi (nil) cg NULL -> [uint32 20000, 20001, 20003]
Scan options:
    conn
    serialcomm
    force_detect
sr: [00:00.044682] hwdriver: sr_config_list(): key 2147418112 (NULL) sdi (nil) cg NULL -> [uint32 20000, 20001, 20003]
sr: [00:00.044742] serial: Opening serial port '/dev/ttyUSB0' (flags 1).
sr: [00:00.047382] serial: Parsing parameters from "9600/8n1".
sr: [00:00.047533] serial: Got params: rate 9600, frame 8/0/1, flow 0, rts -1, dtr -1.
sr: [00:00.047556] serial: Setting serial parameters on port /dev/ttyUSB0.
sr: [00:00.047781] serial: DBG: serial_set_params() rate 9600, 8n1
sr: [00:00.047814] serial: Flushing serial port /dev/ttyUSB0.
sr: [00:00.047836] korad-kaxxxxp: Want max 48 bytes.
sr: [00:00.047874] korad-kaxxxxp: Sending '*IDN?'.
sr: [00:00.047921] serial: Wrote 6/6 bytes.
sr: [00:00.048330] korad-kaxxxxp: want 48 bytes, timeout/retry: init 60/100, later 13/1.
sr: [00:06.063348] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:06.063384] korad-kaxxxxp: Received: 0, 
sr: [00:06.063421] korad-kaxxxxp: Could not find model ID '', trying 'QJE3005PV1.0'.
sr: [00:06.063475] korad-kaxxxxp: Looking up: [QJE3005PV1.0].
sr: [00:06.063510] korad-kaxxxxp: Matches expected ID text: 'QJE3005PV1.0'.
sr: [00:06.063601] korad-kaxxxxp: Found: [Velleman] [LABPS3005DN]
sr: [00:06.063694] korad-kaxxxxp: Found replacement, using it instead.
sr: [00:06.063730] korad-kaxxxxp: Found: Velleman LABPS3005DN (idx 13).
sr: [00:06.063793] korad-kaxxxxp: Sending 'IOUT1?'.
sr: [00:06.063889] serial: Wrote 7/7 bytes.
sr: [00:06.064425] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:07.678406] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:07.678455] korad-kaxxxxp: value: 0.000000
sr: [00:07.678512] korad-kaxxxxp: Sending 'ISET1?'.
sr: [00:07.678714] serial: Wrote 7/7 bytes.
sr: [00:07.679272] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:09.293462] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:09.293510] korad-kaxxxxp: value: 0.000000
sr: [00:09.303754] korad-kaxxxxp: Sending 'VOUT1?'.
sr: [00:09.303904] serial: Wrote 7/7 bytes.
sr: [00:09.304442] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:10.918909] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:10.918962] korad-kaxxxxp: value: 0.000000
sr: [00:10.919034] korad-kaxxxxp: Sending 'VSET1?'.
sr: [00:10.919169] serial: Wrote 7/7 bytes.
sr: [00:10.920004] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:12.534282] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:12.534347] korad-kaxxxxp: value: 0.000000
sr: [00:12.534417] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:12.534505] serial: Wrote 8/8 bytes.
sr: [00:12.535095] korad-kaxxxxp: want 2 bytes, timeout/retry: init 12/100, later 13/1.
sr: [00:13.749701] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:13.749764] korad-kaxxxxp: Status: 0x00
sr: [00:13.749810] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is disabled, OVP is disabled. Device is silent.
sr: [00:13.749970] serial: Closing serial port /dev/ttyUSB0.
sr: [00:13.754861] hwdriver: Scan found 1 devices (korad-kaxxxxp).
sr: [00:13.754999] hwdriver: sr_config_get(): key 20000 (conn) sdi 0x14dbfa10 cg NULL -> '/dev/ttyUSB0'
korad-kaxxxxp:conn=/dev/ttyUSB0 - Velleman LABPS3005DN with 2 channels: V I
sr: [00:13.755065] device: korad-kaxxxxp: Opening device instance.
sr: [00:13.755096] serial: Opening serial port '/dev/ttyUSB0' (flags 1).
sr: [00:13.758369] serial: Parsing parameters from "9600/8n1".
sr: [00:13.758489] serial: Got params: rate 9600, frame 8/0/1, flow 0, rts -1, dtr -1.
sr: [00:13.758536] serial: Setting serial parameters on port /dev/ttyUSB0.
sr: [00:13.758889] serial: DBG: serial_set_params() rate 9600, 8n1
sr: [00:13.758949] serial: Flushing serial port /dev/ttyUSB0.
Supported configuration options:
sr: [00:13.759079] hwdriver: sr_config_get(): key 20000 (conn) sdi 0x14dbfa10 cg NULL -> '/dev/ttyUSB0'
    conn: /dev/ttyUSB0 (current)
    continuous: on, off
sr: [00:13.759219] hwdriver: sr_config_get(): key 50001 (limit_samples) sdi 0x14dbfa10 cg NULL -> uint64 0
    limit_samples: 0 (current)
sr: [00:13.759335] hwdriver: sr_config_get(): key 50000 (limit_time) sdi 0x14dbfa10 cg NULL -> uint64 0
    limit_time: 0 (current)
sr: [00:13.759432] korad-kaxxxxp: Sending 'VOUT1?'.
sr: [00:13.759511] serial: Wrote 7/7 bytes.
sr: [00:13.760007] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:15.373886] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:15.373938] korad-kaxxxxp: value: 0.000000
sr: [00:15.374003] hwdriver: sr_config_get(): key 30029 (voltage) sdi 0x14dbfa10 cg NULL -> 0.0
    voltage: 0.000000 (current)
sr: [00:15.374122] korad-kaxxxxp: Sending 'VSET1?'.
sr: [00:15.374199] serial: Wrote 7/7 bytes.
sr: [00:15.374856] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:16.988147] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:16.988205] korad-kaxxxxp: value: 0.000000
sr: [00:16.988387] hwdriver: sr_config_get(): key 30030 (voltage_target) sdi 0x14dbfa10 cg NULL -> 0.0
sr: [00:16.988522] hwdriver: sr_config_list(): key 30030 (voltage_target) sdi 0x14dbfa10 cg NULL -> [0.0, 31.0, 0.01]
    voltage_target: 0.000000 (current), 31.000000, 0.010000
sr: [00:16.988667] korad-kaxxxxp: Sending 'IOUT1?'.
sr: [00:16.988757] serial: Wrote 7/7 bytes.
sr: [00:16.989392] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:18.603001] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:18.603040] korad-kaxxxxp: value: 0.000000
sr: [00:18.603106] hwdriver: sr_config_get(): key 30031 (current) sdi 0x14dbfa10 cg NULL -> 0.0
    current: 0.000000 (current)
sr: [00:18.603210] korad-kaxxxxp: Sending 'ISET1?'.
sr: [00:18.603290] serial: Wrote 7/7 bytes.
sr: [00:18.603955] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:20.217483] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:20.217544] korad-kaxxxxp: value: 0.000000
sr: [00:20.227778] hwdriver: sr_config_get(): key 30032 (current_limit) sdi 0x14dbfa10 cg NULL -> 0.0
sr: [00:20.227902] hwdriver: sr_config_list(): key 30032 (current_limit) sdi 0x14dbfa10 cg NULL -> [0.0, 5.0999999999999996, 0.001]
    current_limit: 0.000000 (current), 5.100000, 0.001000
sr: [00:20.228139] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:20.228222] serial: Wrote 8/8 bytes.
sr: [00:20.228956] korad-kaxxxxp: want 2 bytes, timeout/retry: init 12/100, later 13/1.
sr: [00:21.437401] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:21.437421] korad-kaxxxxp: Status: 0x00
sr: [00:21.437430] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is disabled, OVP is disabled. Device is silent.
sr: [00:21.437454] hwdriver: sr_config_get(): key 30033 (enabled) sdi 0x14dbfa10 cg NULL -> false
    enabled: on, off (current)
sr: [00:21.437482] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:21.437506] serial: Wrote 8/8 bytes.
sr: [00:21.437913] korad-kaxxxxp: want 2 bytes, timeout/retry: init 12/100, later 13/1.
sr: [00:22.646398] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:22.646433] korad-kaxxxxp: Status: 0x00
sr: [00:22.646462] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is disabled, OVP is disabled. Device is silent.
sr: [00:22.646559] hwdriver: sr_config_get(): key 30043 (regulation) sdi 0x14dbfa10 cg NULL -> 'CC'
    regulation: CC (current)
sr: [00:22.646740] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:22.646920] serial: Wrote 8/8 bytes.
sr: [00:22.647518] korad-kaxxxxp: want 2 bytes, timeout/retry: init 12/100, later 13/1.
sr: [00:23.862576] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:23.862609] korad-kaxxxxp: Status: 0x00
sr: [00:23.862669] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is disabled, OVP is disabled. Device is silent.
sr: [00:23.862736] hwdriver: sr_config_get(): key 30038 (ocp_enabled) sdi 0x14dbfa10 cg NULL -> false
    ocp_enabled: on, off (current)
sr: [00:23.862826] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:23.862910] serial: Wrote 8/8 bytes.
sr: [00:23.863488] korad-kaxxxxp: want 2 bytes, timeout/retry: init 12/100, later 13/1.
sr: [00:25.076744] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:25.076790] korad-kaxxxxp: Status: 0x00
sr: [00:25.076830] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is disabled, OVP is disabled. Device is silent.
sr: [00:25.076899] hwdriver: sr_config_get(): key 30035 (ovp_enabled) sdi 0x14dbfa10 cg NULL -> false
    ovp_enabled: on, off (current)
sr: [00:25.076953] device: korad-kaxxxxp: Closing device instance.
sr: [00:25.076987] serial: Closing serial port /dev/ttyUSB0.
sr: [00:25.081576] hwdriver: Cleaning up all drivers.

@cnf
Copy link

cnf commented May 27, 2025

are you sending a newline, or the actual characters '\n'
mine responds to the actual characterss `'n'

tio /dev/ttyUSB0 -b 9600
.....
[19:19:53.820] INLCRNL is set
*IDN?\nQJE3005PV1.0
STATUS?\n000
VSET1?\n00.00

@MartinJM
Copy link
Author

MartinJM commented May 27, 2025

You're doing nothing wrong, but your device is not responding to the *IDN? request. Otherwise it would show something like the following (which is for my device):

sr: [00:00.001787] serial: Opening serial port '/dev/ttyACM0' (flags 1).
sr: [00:00.002961] serial: Parsing parameters from "9600/8n1".
sr: [00:00.003094] serial: Got params: rate 9600, frame 8/0/1, flow 0, rts -1, dtr -1.
sr: [00:00.003108] serial: Setting serial parameters on port /dev/ttyACM0.
sr: [00:00.003140] serial: DBG: serial_set_params() rate 9600, 8n1
sr: [00:00.003153] serial: Flushing serial port /dev/ttyACM0.
sr: [00:00.003171] korad-kaxxxxp: Want max 48 bytes.
sr: [00:00.003198] korad-kaxxxxp: Sending '*IDN?'.
sr: [00:00.003322] serial: Wrote 6/6 bytes.
sr: [00:00.003358] korad-kaxxxxp: want 48 bytes, timeout/retry: init 60/100, later 13/1.
sr: [00:00.063849] serial: Read 32/48 bytes.
sr: [00:00.077013] korad-kaxxxxp: receive timed out, want 48, received 32.
sr: [00:00.077055] korad-kaxxxxp: got 31 bytes, received: 'KORAD KA3005PS V1.0 SN:........'.
sr: [00:00.077081] korad-kaxxxxp: Received: 31, KORAD KA3005PS V1.0 SN:........
sr: [00:00.077107] korad-kaxxxxp: Looking up: [KORAD KA3005PS V1.0].
sr: [00:00.077169] korad-kaxxxxp: Matches generic '[vendor] model [vers] [trail]' pattern.
sr: [00:00.077896] korad-kaxxxxp: Found: [Korad] [KA3005PS]
sr: [00:00.078028] korad-kaxxxxp: Found: Korad KA3005PS (idx 0).

Also just read your original diff again: and noticed that you're actually adding a literal backslash and then n character. Which may make it work.

Can you try the following patch? It will take a while to connect, but might work for your device:

diff --git a/src/hardware/korad-kaxxxxp/api.c b/src/hardware/korad-kaxxxxp/api.c
index c6b9b1f6..824303f1 100644
--- a/src/hardware/korad-kaxxxxp/api.c
+++ b/src/hardware/korad-kaxxxxp/api.c
@@ -76,6 +76,8 @@ static const struct korad_kaxxxxp_model models[] = {
 	{"Tenma", "72-2710", "", 1, volts_30, amps_5, 0},
 	{"Velleman", "LABPS3005D", "", 1, volts_30, amps_5,
 		KORAD_QUIRK_LABPS_OVP_EN},
+	{"Velleman", "LABPS3005DN", "", 1, volts_30, amps_5,
+		KORAD_QUIRK_NEWLINE | KORAD_QUIRK_VELLEMAN},
 	{"Velleman", "PS3005D V1.3", "VELLEMANPS3005DV1.3" , 1, volts_30, amps_5,
 		KORAD_QUIRK_ID_TRAILING | KORAD_QUIRK_SLOW_PROCESSING},
 	{"Velleman", "PS3005D", "", 1, volts_30, amps_5, 0},
@@ -290,6 +292,17 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 	ret = korad_kaxxxxp_read_chars(serial, len, reply, true);
 	if (ret < 0)
 		return NULL;
+
+	// Also attempt literal \\n for VELLMAN
+	if (ret == 0) {
+		ret = korad_kaxxxxp_send_cmd(serial, "*IDN?\\n", true);
+		if (ret < 0)
+			return NULL;
+
+		ret = korad_kaxxxxp_read_chars(serial, len, reply, true);
+		if (ret < 0)
+			return NULL;
+	}
 	sr_dbg("Received: %d, %s", ret, reply);
 
 	/*
diff --git a/src/hardware/korad-kaxxxxp/protocol.c b/src/hardware/korad-kaxxxxp/protocol.c
index 0ce7206e..b27d8f9c 100644
--- a/src/hardware/korad-kaxxxxp/protocol.c
+++ b/src/hardware/korad-kaxxxxp/protocol.c
@@ -229,8 +229,13 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
 			"VSET1:%05.2f", devc->set_voltage_target);
 		break;
 	case KAXXXXP_OUTPUT:
-		sr_snprintf_ascii(msg, sizeof(msg),
-			"OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		if (devc->model->quirks & KORAD_QUIRK_VELLEMAN) {
+			sr_snprintf_ascii(msg, sizeof(msg),
+				"OUTPUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		} else {
+			sr_snprintf_ascii(msg, sizeof(msg),
+				"OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		}
 		/* Set value back to recognize changes */
 		devc->output_enabled = devc->set_output_enabled;
 		break;
diff --git a/src/hardware/korad-kaxxxxp/protocol.h b/src/hardware/korad-kaxxxxp/protocol.h
index 43653d14..19aef882 100644
--- a/src/hardware/korad-kaxxxxp/protocol.h
+++ b/src/hardware/korad-kaxxxxp/protocol.h
@@ -40,7 +40,8 @@ enum korad_quirks_flag {
 	KORAD_QUIRK_ID_OPT_VERSION = 1UL << 3,
 	KORAD_QUIRK_SLOW_PROCESSING = 1UL << 4,
 	KORAD_QUIRK_NEWLINE = 1UL << 5,
-	KORAD_QUIRK_ALL = (1UL << 6) - 1,
+	KORAD_QUIRK_VELLEMAN = 1UL << 6,
+	KORAD_QUIRK_ALL = (1UL << 7) - 1,
 };
 
 /* Information on single model */

Might also be necessary for the other commands, not sure yet, we will see. Another option could be to change the \n from the protocol.c to a \r, but lets take it one step at a time.

@MartinJM
Copy link
Author

MartinJM commented May 27, 2025

are you sending a newline, or the actual characters '\n'

Newlines. Only noticed that you meant the actual characters just before my previous comment.

For my device it's about newlines (or carriage-returns). A literal \\n is very weird to me.


Edit:

This clears up a lot:

tio /dev/ttyUSB0 -b 9600
.....
[19:19:53.820] INLCRNL is set
*IDN?\nQJE3005PV1.0
STATUS?\n000
VSET1?\n00.00

Try the following patch:

diff --git a/src/hardware/korad-kaxxxxp/api.c b/src/hardware/korad-kaxxxxp/api.c
index c6b9b1f6..30d5d36a 100644
--- a/src/hardware/korad-kaxxxxp/api.c
+++ b/src/hardware/korad-kaxxxxp/api.c
@@ -76,6 +76,8 @@ static const struct korad_kaxxxxp_model models[] = {
 	{"Tenma", "72-2710", "", 1, volts_30, amps_5, 0},
 	{"Velleman", "LABPS3005D", "", 1, volts_30, amps_5,
 		KORAD_QUIRK_LABPS_OVP_EN},
+	{"Velleman", "LABPS3005DN", "", 1, volts_30, amps_5,
+		KORAD_QUIRK_VELLEMAN},
 	{"Velleman", "PS3005D V1.3", "VELLEMANPS3005DV1.3" , 1, volts_30, amps_5,
 		KORAD_QUIRK_ID_TRAILING | KORAD_QUIRK_SLOW_PROCESSING},
 	{"Velleman", "PS3005D", "", 1, volts_30, amps_5, 0},
@@ -282,7 +284,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 
 	// TODO: check if adding the newline breaks some other devices - I cannot do so
 	// This is required for the KA3005PS
-	ret = korad_kaxxxxp_send_cmd(serial, "*IDN?", true);
+	// TODO: check if adding the \\n breaks some other devices - I cannot do so
+	// This is required for the Velleman LABPS3005DN
+	// It does not break the KA3005PS
+	ret = korad_kaxxxxp_send_cmd(serial, "*IDN?", true, true);
 	if (ret < 0)
 		return NULL;
 
@@ -290,6 +295,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 	ret = korad_kaxxxxp_read_chars(serial, len, reply, true);
 	if (ret < 0)
 		return NULL;
+
 	sr_dbg("Received: %d, %s", ret, reply);
 
 	/*
diff --git a/src/hardware/korad-kaxxxxp/protocol.c b/src/hardware/korad-kaxxxxp/protocol.c
index 0ce7206e..76672e4c 100644
--- a/src/hardware/korad-kaxxxxp/protocol.c
+++ b/src/hardware/korad-kaxxxxp/protocol.c
@@ -25,18 +25,22 @@
 #define EXTRA_PROCESSING_TIME_MS  450
 
 SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
-	const char *cmd, bool add_newline)
+	const char *cmd, bool add_newline, bool velleman_literal)
 {
 	int ret;
 
 	char* addition = "";
-	if (add_newline)
+	if (add_newline && velleman_literal)
+		addition = "\\n\n";
+	else if (add_newline)
 		addition = "\n";
+	else if (velleman_literal)
+		addition = "\\n"; // Very weird one
 
-	// 21 was chosen here because 20 is chosen in korad_kaxxxxp_set_value
-	char newcmd[21];
-	ret = sr_snprintf_ascii(newcmd, 21, "%s%s", cmd, addition);
-	if (ret < 0 || ret >= 21) {
+	// 23 was chosen here because 20 is chosen in korad_kaxxxxp_set_value
+	char newcmd[23];
+	ret = sr_snprintf_ascii(newcmd, sizeof(newcmd), "%s%s", cmd, addition);
+	if (ret < 0 || ret >= (int) sizeof(newcmd)) {
 		sr_err("Error creating command: %d.", ret);
 		if (ret > 0)
 			ret = -ret; // make errors always return negative numbers
@@ -229,8 +233,13 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
 			"VSET1:%05.2f", devc->set_voltage_target);
 		break;
 	case KAXXXXP_OUTPUT:
-		sr_snprintf_ascii(msg, sizeof(msg),
-			"OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		if (devc->model->quirks & KORAD_QUIRK_VELLEMAN) {
+			sr_snprintf_ascii(msg, sizeof(msg),
+				"OUTPUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		} else {
+			sr_snprintf_ascii(msg, sizeof(msg),
+				"OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		}
 		/* Set value back to recognize changes */
 		devc->output_enabled = devc->set_output_enabled;
 		break;
@@ -277,7 +286,8 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
 	}
 
 	if (ret == SR_OK && msg[0]) {
-		ret = korad_kaxxxxp_send_cmd(serial, msg, devc->model->quirks & KORAD_QUIRK_NEWLINE);
+		ret = korad_kaxxxxp_send_cmd(serial, msg, devc->model->quirks & KORAD_QUIRK_NEWLINE,
+			devc->model->quirks & KORAD_QUIRK_VELLEMAN);
 		devc->next_req_time = next_req_time(devc, TRUE, target);
 	}
 
@@ -303,26 +313,27 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
 	count = 6;
 
 	bool newline_quirk = devc->model->quirks & KORAD_QUIRK_NEWLINE;
+	bool velleman_quirk = devc->model->quirks & KORAD_QUIRK_VELLEMAN;
 
 	switch (target) {
 	case KAXXXXP_CURRENT:
 		/* Read current from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?", newline_quirk, velleman_quirk);
 		value = &(devc->current);
 		break;
 	case KAXXXXP_CURRENT_LIMIT:
 		/* Read set current from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "ISET1?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "ISET1?", newline_quirk, velleman_quirk);
 		value = &(devc->current_limit);
 		break;
 	case KAXXXXP_VOLTAGE:
 		/* Read voltage from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?", newline_quirk, velleman_quirk);
 		value = &(devc->voltage);
 		break;
 	case KAXXXXP_VOLTAGE_TARGET:
 		/* Read set voltage from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "VSET1?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "VSET1?", newline_quirk, velleman_quirk);
 		value = &(devc->voltage_target);
 		break;
 	case KAXXXXP_STATUS:
@@ -330,7 +341,7 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
 	case KAXXXXP_OCP:
 	case KAXXXXP_OVP:
 		/* Read status from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "STATUS?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "STATUS?", newline_quirk, velleman_quirk);
 		count = 1;
 		if (newline_quirk)
 			count = 2;
diff --git a/src/hardware/korad-kaxxxxp/protocol.h b/src/hardware/korad-kaxxxxp/protocol.h
index 43653d14..4540c831 100644
--- a/src/hardware/korad-kaxxxxp/protocol.h
+++ b/src/hardware/korad-kaxxxxp/protocol.h
@@ -40,7 +40,8 @@ enum korad_quirks_flag {
 	KORAD_QUIRK_ID_OPT_VERSION = 1UL << 3,
 	KORAD_QUIRK_SLOW_PROCESSING = 1UL << 4,
 	KORAD_QUIRK_NEWLINE = 1UL << 5,
-	KORAD_QUIRK_ALL = (1UL << 6) - 1,
+	KORAD_QUIRK_VELLEMAN = 1UL << 6,
+	KORAD_QUIRK_ALL = (1UL << 7) - 1,
 };
 
 /* Information on single model */
@@ -105,7 +106,7 @@ struct dev_context {
 };
 
 SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
-		const char *cmd, bool add_newline);
+		const char *cmd, bool add_newline, bool velleman_literal);
 SR_PRIV int korad_kaxxxxp_read_chars(struct sr_serial_dev_inst *serial,
 		size_t count, char *buf, bool strip_newline);
 SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,

I doubt it will work at once, you'll probably need something like QJE3005PV1.0 instead of LABPS3005DN, but I'm unfamiliar with how that should be implemented exactly (as it contains version information, and something different from what the documentation suggests?).

And maybe you also need the newline quirk? I don't think you do so I've removed it from the quirks now, but if it doesn't work, you can try adding it again as well.

@cnf
Copy link

cnf commented May 27, 2025

are you sending a newline, or the actual characters '\n'

Newlines. Only noticed that you meant the actual characters just before my previous comment.

For my device it's about newlines (or carriage-returns). A literal \\n is very weird to me.

A literal '\n' is very weird to me, too! idno what the person that wrote that was smoking :P

sr: [00:00.020582] hwdriver: sr_config_list(): key 2147418112 (NULL) sdi (nil) cg NULL -> [uint32 20000, 20001, 20003]
sr: [00:00.020610] serial: Opening serial port '/dev/ttyUSB0' (flags 1).
sr: [00:00.022520] serial: Parsing parameters from "9600/8n1".
sr: [00:00.022623] serial: Got params: rate 9600, frame 8/0/1, flow 0, rts -1, dtr -1.
sr: [00:00.022644] serial: Setting serial parameters on port /dev/ttyUSB0.
sr: [00:00.022838] serial: DBG: serial_set_params() rate 9600, 8n1
sr: [00:00.022860] serial: Flushing serial port /dev/ttyUSB0.
sr: [00:00.022883] korad-kaxxxxp: Want max 48 bytes.
sr: [00:00.022896] korad-kaxxxxp: Sending '*IDN?'.
sr: [00:00.022919] serial: Wrote 6/6 bytes.
sr: [00:00.023272] korad-kaxxxxp: want 48 bytes, timeout/retry: init 60/100, later 13/1.
sr: [00:06.036559] korad-kaxxxxp: got 0 bytes, received: ''.
sr: [00:06.036611] korad-kaxxxxp: Sending '*IDN?\n'.
sr: [00:06.036733] serial: Wrote 7/7 bytes.
sr: [00:06.037321] korad-kaxxxxp: want 48 bytes, timeout/retry: init 60/100, later 13/1.
sr: [00:06.097543] serial: Read 13/48 bytes.
sr: [00:06.110754] korad-kaxxxxp: receive timed out, want 48, received 13.
sr: [00:06.110794] korad-kaxxxxp: got 12 bytes, received: 'QJE3005PV1.0'.
sr: [00:06.110866] korad-kaxxxxp: Received: 12, QJE3005PV1.0
sr: [00:06.110907] korad-kaxxxxp: Looking up: [QJE3005PV1.0].
sr: [00:06.110945] korad-kaxxxxp: Matches expected ID text: 'QJE3005PV1.0'.
sr: [00:06.110981] korad-kaxxxxp: Found: [Velleman] [LABPS3005DN]
sr: [00:06.111013] korad-kaxxxxp: Found: Velleman LABPS3005DN (idx 13).
sr: [00:06.111060] korad-kaxxxxp: Sending 'IOUT1?'.

So I changed your last patch a bit,
it responds to *IDN?\n with QJE3005PV1.0' so i added that to:

+	{"Velleman", "LABPS3005DN", "QJE3005PV1.0", 1, volts_30, amps_5,
+		KORAD_QUIRK_NEWLINE | KORAD_QUIRK_VELLEMAN},

And I changed

ret = korad_kaxxxxp_send_cmd(serial, "*IDN?\\n", true);

to

ret = korad_kaxxxxp_send_cmd(serial, "*IDN?\\n", false);

It seems it doesn't like ACTUAL newlines, at that 🤦

It now gets detected, but of course the rest doesn't work, because actual \n instead of a newline :P

@MartinJM
Copy link
Author

MartinJM commented May 27, 2025

Ah I just edited my previous response. See the patch there, that might still need some of your edits.

It seems it doesn't like ACTUAL newlines, at that 🤦

Ah that will be an issue for supporting both of our devices then. Mine must have a newline, and yours cannot have one... Maybe one different option: Can you try it with a carriage return (\r) instead of a newline? That works on my device as well, if it works on yours too it could be a nice middle-road.


Edit: Oh yeah your STATUS? response also seems way different. I don't think it's likely to work at the moment.

@cnf
Copy link

cnf commented May 27, 2025

that last one isn't detecting it anymore at all... I'll poke at it some more tomorrow, thanks for the help!

@cnf
Copy link

cnf commented May 28, 2025

ok, you last patch works, if I change:

Add QJE3005PV1.0
+       {"Velleman", "LABPS3005DN", "QJE3005PV1.0", 1, volts_30, amps_5,
+               KORAD_QUIRK_VELLEMAN},
set add_newline to false in the discovery
ret = korad_kaxxxxp_send_cmd(serial, "*IDN?", false, true);
So the patch that works atm is
diff --git a/src/hardware/korad-kaxxxxp/api.c b/src/hardware/korad-kaxxxxp/api.c
index c6b9b1f6..30d5d36a 100644
--- a/src/hardware/korad-kaxxxxp/api.c
+++ b/src/hardware/korad-kaxxxxp/api.c
@@ -76,6 +76,8 @@ static const struct korad_kaxxxxp_model models[] = {
 	{"Tenma", "72-2710", "", 1, volts_30, amps_5, 0},
 	{"Velleman", "LABPS3005D", "", 1, volts_30, amps_5,
 		KORAD_QUIRK_LABPS_OVP_EN},
+	{"Velleman", "LABPS3005DN", "QJE3005PV1.0", 1, volts_30, amps_5,
+		KORAD_QUIRK_VELLEMAN},
 	{"Velleman", "PS3005D V1.3", "VELLEMANPS3005DV1.3" , 1, volts_30, amps_5,
 		KORAD_QUIRK_ID_TRAILING | KORAD_QUIRK_SLOW_PROCESSING},
 	{"Velleman", "PS3005D", "", 1, volts_30, amps_5, 0},
@@ -282,7 +284,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 
 	// TODO: check if adding the newline breaks some other devices - I cannot do so
 	// This is required for the KA3005PS
-	ret = korad_kaxxxxp_send_cmd(serial, "*IDN?", true);
+	// TODO: check if adding the \\n breaks some other devices - I cannot do so
+	// This is required for the Velleman LABPS3005DN
+	// It does not break the KA3005PS
+	ret = korad_kaxxxxp_send_cmd(serial, "*IDN?", false, true);
 	if (ret < 0)
 		return NULL;
 
@@ -290,6 +295,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
 	ret = korad_kaxxxxp_read_chars(serial, len, reply, true);
 	if (ret < 0)
 		return NULL;
+
 	sr_dbg("Received: %d, %s", ret, reply);
 
 	/*
diff --git a/src/hardware/korad-kaxxxxp/protocol.c b/src/hardware/korad-kaxxxxp/protocol.c
index 0ce7206e..76672e4c 100644
--- a/src/hardware/korad-kaxxxxp/protocol.c
+++ b/src/hardware/korad-kaxxxxp/protocol.c
@@ -25,18 +25,22 @@
 #define EXTRA_PROCESSING_TIME_MS  450
 
 SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
-	const char *cmd, bool add_newline)
+	const char *cmd, bool add_newline, bool velleman_literal)
 {
 	int ret;
 
 	char* addition = "";
-	if (add_newline)
+	if (add_newline && velleman_literal)
+		addition = "\\n\n";
+	else if (add_newline)
 		addition = "\n";
+	else if (velleman_literal)
+		addition = "\\n"; // Very weird one
 
-	// 21 was chosen here because 20 is chosen in korad_kaxxxxp_set_value
-	char newcmd[21];
-	ret = sr_snprintf_ascii(newcmd, 21, "%s%s", cmd, addition);
-	if (ret < 0 || ret >= 21) {
+	// 23 was chosen here because 20 is chosen in korad_kaxxxxp_set_value
+	char newcmd[23];
+	ret = sr_snprintf_ascii(newcmd, sizeof(newcmd), "%s%s", cmd, addition);
+	if (ret < 0 || ret >= (int) sizeof(newcmd)) {
 		sr_err("Error creating command: %d.", ret);
 		if (ret > 0)
 			ret = -ret; // make errors always return negative numbers
@@ -229,8 +233,13 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
 			"VSET1:%05.2f", devc->set_voltage_target);
 		break;
 	case KAXXXXP_OUTPUT:
-		sr_snprintf_ascii(msg, sizeof(msg),
-			"OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		if (devc->model->quirks & KORAD_QUIRK_VELLEMAN) {
+			sr_snprintf_ascii(msg, sizeof(msg),
+				"OUTPUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		} else {
+			sr_snprintf_ascii(msg, sizeof(msg),
+				"OUT%1d", (devc->set_output_enabled) ? 1 : 0);
+		}
 		/* Set value back to recognize changes */
 		devc->output_enabled = devc->set_output_enabled;
 		break;
@@ -277,7 +286,8 @@ SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,
 	}
 
 	if (ret == SR_OK && msg[0]) {
-		ret = korad_kaxxxxp_send_cmd(serial, msg, devc->model->quirks & KORAD_QUIRK_NEWLINE);
+		ret = korad_kaxxxxp_send_cmd(serial, msg, devc->model->quirks & KORAD_QUIRK_NEWLINE,
+			devc->model->quirks & KORAD_QUIRK_VELLEMAN);
 		devc->next_req_time = next_req_time(devc, TRUE, target);
 	}
 
@@ -303,26 +313,27 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
 	count = 6;
 
 	bool newline_quirk = devc->model->quirks & KORAD_QUIRK_NEWLINE;
+	bool velleman_quirk = devc->model->quirks & KORAD_QUIRK_VELLEMAN;
 
 	switch (target) {
 	case KAXXXXP_CURRENT:
 		/* Read current from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "IOUT1?", newline_quirk, velleman_quirk);
 		value = &(devc->current);
 		break;
 	case KAXXXXP_CURRENT_LIMIT:
 		/* Read set current from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "ISET1?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "ISET1?", newline_quirk, velleman_quirk);
 		value = &(devc->current_limit);
 		break;
 	case KAXXXXP_VOLTAGE:
 		/* Read voltage from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "VOUT1?", newline_quirk, velleman_quirk);
 		value = &(devc->voltage);
 		break;
 	case KAXXXXP_VOLTAGE_TARGET:
 		/* Read set voltage from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "VSET1?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "VSET1?", newline_quirk, velleman_quirk);
 		value = &(devc->voltage_target);
 		break;
 	case KAXXXXP_STATUS:
@@ -330,7 +341,7 @@ SR_PRIV int korad_kaxxxxp_get_value(struct sr_serial_dev_inst *serial,
 	case KAXXXXP_OCP:
 	case KAXXXXP_OVP:
 		/* Read status from device. */
-		ret = korad_kaxxxxp_send_cmd(serial, "STATUS?", newline_quirk);
+		ret = korad_kaxxxxp_send_cmd(serial, "STATUS?", newline_quirk, velleman_quirk);
 		count = 1;
 		if (newline_quirk)
 			count = 2;
diff --git a/src/hardware/korad-kaxxxxp/protocol.h b/src/hardware/korad-kaxxxxp/protocol.h
index 43653d14..4540c831 100644
--- a/src/hardware/korad-kaxxxxp/protocol.h
+++ b/src/hardware/korad-kaxxxxp/protocol.h
@@ -40,7 +40,8 @@ enum korad_quirks_flag {
 	KORAD_QUIRK_ID_OPT_VERSION = 1UL << 3,
 	KORAD_QUIRK_SLOW_PROCESSING = 1UL << 4,
 	KORAD_QUIRK_NEWLINE = 1UL << 5,
-	KORAD_QUIRK_ALL = (1UL << 6) - 1,
+	KORAD_QUIRK_VELLEMAN = 1UL << 6,
+	KORAD_QUIRK_ALL = (1UL << 7) - 1,
 };
 
 /* Information on single model */
@@ -105,7 +106,7 @@ struct dev_context {
 };
 
 SR_PRIV int korad_kaxxxxp_send_cmd(struct sr_serial_dev_inst *serial,
-		const char *cmd, bool add_newline);
+		const char *cmd, bool add_newline, bool velleman_literal);
 SR_PRIV int korad_kaxxxxp_read_chars(struct sr_serial_dev_inst *serial,
 		size_t count, char *buf, bool strip_newline);
 SR_PRIV int korad_kaxxxxp_set_value(struct sr_serial_dev_inst *serial,

log:

± sigrok-cli -d korad-kaxxxxp:conn=/dev/ttyUSB0 -l 5 --show 
sr: [00:00.000044] log: libsigrok loglevel set to 5.
sr: [00:00.000067] backend: libsigrok 0.6.0/4:0:0.
sr: [00:00.000157] backend: Libs: glib 2.82.5 (rt: 2.82.5/8205:5), zlib 1.3.1, libzip 1.11.3, minilzo 2.10, libserialport 0.1.1/1:0:1 (rt: 0.1.1/1:0:1), libusb-1.0 1.0.27.11882 API 0x0100010a, hidapi 0.14.0, bluez 5.79, libftdi 1.5.
sr: [00:00.000195] backend: Host: x86_64-pc-linux-gnu, little-endian.
sr: [00:00.000222] backend: SCPI backends: TCP, serial, USBTMC.
sr: [00:00.000258] backend: Firmware search paths:
sr: [00:00.000316] backend:  - /home/cnf/.local/share/sigrok-firmware
sr: [00:00.000338] backend:  - /nix/store/7jc15rv458d6zj247dcj5lwxysl6sppw-libsigrok-0.5.2-unstable-2024-10-20/share/sigrok-firmware
sr: [00:00.000375] backend:  - /nix/store/y2m5aj2saaafp2fqa2rp8v0qlbzjmihb-network-manager-applet-1.36.0/share/sigrok-firmware
sr: [00:00.000411] backend:  - /nix/store/ciigf79sbx1pckyyjzzv9nrny96lrijf-gnome-mimeapps/share/sigrok-firmware
sr: [00:00.000448] backend:  - /nix/store/m3cndj0jvn72ri17pmd6yz83d582186r-desktops/share/sigrok-firmware
sr: [00:00.000476] backend:  - /home/cnf/.nix-profile/share/sigrok-firmware
sr: [00:00.000499] backend:  - /nix/profile/share/sigrok-firmware
sr: [00:00.000524] backend:  - /home/cnf/.local/state/nix/profile/share/sigrok-firmware
sr: [00:00.000548] backend:  - /etc/profiles/per-user/cnf/share/sigrok-firmware
sr: [00:00.000579] backend:  - /nix/var/nix/profiles/default/share/sigrok-firmware
sr: [00:00.000598] backend:  - /run/current-system/sw/share/sigrok-firmware
sr: [00:00.000619] backend:  - /nix/store/ibzdvd08vnfzihyq9k4h9c3m2ghi5sp2-gnome-shell-47.2/share/gsettings-schemas/gnome-shell-47.2/sigrok-firmware
sr: [00:00.000645] backend:  - /nix/store/57kcdgar0vnchc9f2049hlwj9cjl4p3s-gnome-shell-extensions-47.2/share/gsettings-schemas/gnome-shell-extensions-47.2/sigrok-firmware
sr: [00:00.000736] backend: Sanity-checking all drivers.
sr: [00:00.000776] backend: Sanity-checking all input modules.
sr: [00:00.000835] backend: Sanity-checking all output modules.
sr: [00:00.000884] backend: Sanity-checking all transform modules.
srd: libsigrokdecode loglevel set to 5.
Driver functions:
    Power supply
sr: [00:00.019758] hwdriver: sr_config_list(): key 2147418112 (NULL) sdi (nil) cg NULL -> [uint32 20000, 20001, 20003]
Scan options:
    conn
    serialcomm
    force_detect
sr: [00:00.019823] hwdriver: sr_config_list(): key 2147418112 (NULL) sdi (nil) cg NULL -> [uint32 20000, 20001, 20003]
sr: [00:00.019841] serial: Opening serial port '/dev/ttyUSB0' (flags 1).
sr: [00:00.021879] serial: Parsing parameters from "9600/8n1".
sr: [00:00.021972] serial: Got params: rate 9600, frame 8/0/1, flow 0, rts -1, dtr -1.
sr: [00:00.022006] serial: Setting serial parameters on port /dev/ttyUSB0.
sr: [00:00.022181] serial: DBG: serial_set_params() rate 9600, 8n1
sr: [00:00.022197] serial: Flushing serial port /dev/ttyUSB0.
sr: [00:00.022211] korad-kaxxxxp: Want max 48 bytes.
sr: [00:00.022234] korad-kaxxxxp: Sending '*IDN?'.
sr: [00:00.022258] serial: Wrote 7/7 bytes.
sr: [00:00.022708] korad-kaxxxxp: want 48 bytes, timeout/retry: init 60/100, later 13/1.
sr: [00:00.082833] serial: Read 13/48 bytes.
sr: [00:00.095978] korad-kaxxxxp: receive timed out, want 48, received 13.
sr: [00:00.096012] korad-kaxxxxp: got 12 bytes, received: 'QJE3005PV1.0'.
sr: [00:00.096052] korad-kaxxxxp: Received: 12, QJE3005PV1.0
sr: [00:00.096093] korad-kaxxxxp: Looking up: [QJE3005PV1.0].
sr: [00:00.096172] korad-kaxxxxp: Matches expected ID text: 'QJE3005PV1.0'.
sr: [00:00.096209] korad-kaxxxxp: Found: [Velleman] [LABPS3005DN]
sr: [00:00.096249] korad-kaxxxxp: Found: Velleman LABPS3005DN (idx 13).
sr: [00:00.096311] korad-kaxxxxp: Sending 'IOUT1?'.
sr: [00:00.096394] serial: Wrote 8/8 bytes.
sr: [00:00.097183] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:00.123354] serial: Read 6/6 bytes.
sr: [00:00.123412] korad-kaxxxxp: got 6 bytes, received: '0.000'.
sr: [00:00.123523] korad-kaxxxxp: value: 0.000000
sr: [00:00.176607] korad-kaxxxxp: Sleeping for processing 52889 usec
sr: [00:00.176685] korad-kaxxxxp: Sending 'ISET1?'.
sr: [00:00.176776] serial: Wrote 8/8 bytes.
sr: [00:00.177315] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:00.193509] serial: Read 4/6 bytes.
sr: [00:00.195488] serial: Read 2/2 bytes.
sr: [00:00.195541] korad-kaxxxxp: got 6 bytes, received: '0.000'.
sr: [00:00.195588] korad-kaxxxxp: value: 0.000000
sr: [00:00.256965] korad-kaxxxxp: Sleeping for processing 50920 usec
sr: [00:00.257006] korad-kaxxxxp: Sending 'VOUT1?'.
sr: [00:00.257115] serial: Wrote 8/8 bytes.
sr: [00:00.257822] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:00.274020] serial: Read 3/6 bytes.
sr: [00:00.277123] serial: Read 3/3 bytes.
sr: [00:00.277175] korad-kaxxxxp: got 6 bytes, received: '00.00'.
sr: [00:00.277234] korad-kaxxxxp: value: 0.000000
sr: [00:00.337279] korad-kaxxxxp: Sleeping for processing 59850 usec
sr: [00:00.337319] korad-kaxxxxp: Sending 'VSET1?'.
sr: [00:00.337470] serial: Wrote 8/8 bytes.
sr: [00:00.338039] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:00.360935] serial: Read 6/6 bytes.
sr: [00:00.360991] korad-kaxxxxp: got 6 bytes, received: '08.00'.
sr: [00:00.361036] korad-kaxxxxp: value: 0.000000
sr: [00:00.417643] korad-kaxxxxp: Sleeping for processing 56433 usec
sr: [00:00.417709] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:00.417820] serial: Wrote 9/9 bytes.
sr: [00:00.418461] korad-kaxxxxp: want 1 bytes, timeout/retry: init 11/100, later 13/1.
sr: [00:00.437977] serial: Read 1/1 bytes.
sr: [00:00.438010] korad-kaxxxxp: got 1 bytes, received: '0'.
sr: [00:00.438047] korad-kaxxxxp: Status: 0x30
sr: [00:00.438098] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is enabled, OVP is disabled. Device is beeping.
sr: [00:00.438149] serial: Closing serial port /dev/ttyUSB0.
sr: [00:00.441167] hwdriver: Scan found 1 devices (korad-kaxxxxp).
sr: [00:00.441321] hwdriver: sr_config_get(): key 20000 (conn) sdi 0x332819f0 cg NULL -> '/dev/ttyUSB0'
korad-kaxxxxp:conn=/dev/ttyUSB0 - Velleman LABPS3005DN with 2 channels: V I
sr: [00:00.441395] device: korad-kaxxxxp: Opening device instance.
sr: [00:00.441476] serial: Opening serial port '/dev/ttyUSB0' (flags 1).
sr: [00:00.444366] serial: Parsing parameters from "9600/8n1".
sr: [00:00.444524] serial: Got params: rate 9600, frame 8/0/1, flow 0, rts -1, dtr -1.
sr: [00:00.444566] serial: Setting serial parameters on port /dev/ttyUSB0.
sr: [00:00.444950] serial: DBG: serial_set_params() rate 9600, 8n1
sr: [00:00.445010] serial: Flushing serial port /dev/ttyUSB0.
Supported configuration options:
sr: [00:00.445141] hwdriver: sr_config_get(): key 20000 (conn) sdi 0x332819f0 cg NULL -> '/dev/ttyUSB0'
    conn: /dev/ttyUSB0 (current)
    continuous: on, off
sr: [00:00.445339] hwdriver: sr_config_get(): key 50001 (limit_samples) sdi 0x332819f0 cg NULL -> uint64 0
    limit_samples: 0 (current)
sr: [00:00.445475] hwdriver: sr_config_get(): key 50000 (limit_time) sdi 0x332819f0 cg NULL -> uint64 0
    limit_time: 0 (current)
sr: [00:00.498095] korad-kaxxxxp: Sleeping for processing 52367 usec
sr: [00:00.498153] korad-kaxxxxp: Sending 'VOUT1?'.
sr: [00:00.498238] serial: Wrote 8/8 bytes.
sr: [00:00.498780] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:00.523378] serial: Read 6/6 bytes.
sr: [00:00.523411] korad-kaxxxxp: got 6 bytes, received: '00.00'.
sr: [00:00.523478] korad-kaxxxxp: value: 0.000000
sr: [00:00.523562] hwdriver: sr_config_get(): key 30029 (voltage) sdi 0x332819f0 cg NULL -> 0.0
    voltage: 0.000000 (current)
sr: [00:00.578439] korad-kaxxxxp: Sleeping for processing 54614 usec
sr: [00:00.578515] korad-kaxxxxp: Sending 'VSET1?'.
sr: [00:00.578597] serial: Wrote 8/8 bytes.
sr: [00:00.579164] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:00.595371] serial: Read 5/6 bytes.
sr: [00:00.596127] serial: Read 1/1 bytes.
sr: [00:00.596216] korad-kaxxxxp: got 6 bytes, received: '08.00'.
sr: [00:00.596256] korad-kaxxxxp: value: 0.000000
sr: [00:00.596321] hwdriver: sr_config_get(): key 30030 (voltage_target) sdi 0x332819f0 cg NULL -> 0.0
sr: [00:00.596480] hwdriver: sr_config_list(): key 30030 (voltage_target) sdi 0x332819f0 cg NULL -> [0.0, 31.0, 0.01]
    voltage_target: 0.000000 (current), 31.000000, 0.010000
sr: [00:00.658790] korad-kaxxxxp: Sleeping for processing 62042 usec
sr: [00:00.658856] korad-kaxxxxp: Sending 'IOUT1?'.
sr: [00:00.658998] serial: Wrote 8/8 bytes.
sr: [00:00.659635] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:00.675800] serial: Read 3/6 bytes.
sr: [00:00.678969] serial: Read 3/3 bytes.
sr: [00:00.679004] korad-kaxxxxp: got 6 bytes, received: '0.000'.
sr: [00:00.679048] korad-kaxxxxp: value: 0.000000
sr: [00:00.679112] hwdriver: sr_config_get(): key 30031 (current) sdi 0x332819f0 cg NULL -> 0.0
    current: 0.000000 (current)
sr: [00:00.739187] korad-kaxxxxp: Sleeping for processing 59813 usec
sr: [00:00.739225] korad-kaxxxxp: Sending 'ISET1?'.
sr: [00:00.739325] serial: Wrote 8/8 bytes.
sr: [00:00.739917] korad-kaxxxxp: want 6 bytes, timeout/retry: init 16/100, later 13/1.
sr: [00:00.756155] serial: Read 2/6 bytes.
sr: [00:00.759942] serial: Read 4/4 bytes.
sr: [00:00.759987] korad-kaxxxxp: got 6 bytes, received: '0.000'.
sr: [00:00.760027] korad-kaxxxxp: value: 0.000000
sr: [00:00.770296] hwdriver: sr_config_get(): key 30032 (current_limit) sdi 0x332819f0 cg NULL -> 0.0
sr: [00:00.770448] hwdriver: sr_config_list(): key 30032 (current_limit) sdi 0x332819f0 cg NULL -> [0.0, 5.0999999999999996, 0.001]
    current_limit: 0.000000 (current), 5.100000, 0.001000
sr: [00:00.819532] korad-kaxxxxp: Sleeping for processing 48801 usec
sr: [00:00.819581] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:00.819769] serial: Wrote 9/9 bytes.
sr: [00:00.820323] korad-kaxxxxp: want 1 bytes, timeout/retry: init 11/100, later 13/1.
sr: [00:00.836844] serial: Read 1/1 bytes.
sr: [00:00.836897] korad-kaxxxxp: got 1 bytes, received: '0'.
sr: [00:00.836940] korad-kaxxxxp: Status: 0x30
sr: [00:00.836979] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is enabled, OVP is disabled. Device is beeping.
sr: [00:00.837043] hwdriver: sr_config_get(): key 30033 (enabled) sdi 0x332819f0 cg NULL -> false
    enabled: on, off (current)
sr: [00:00.899966] korad-kaxxxxp: Sleeping for processing 62699 usec
sr: [00:00.900026] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:00.900125] serial: Wrote 9/9 bytes.
sr: [00:00.900817] korad-kaxxxxp: want 1 bytes, timeout/retry: init 11/100, later 13/1.
sr: [00:00.900910] serial: Read 1/1 bytes.
sr: [00:00.900949] korad-kaxxxxp: got 1 bytes, received: '0'.
sr: [00:00.900994] korad-kaxxxxp: Status: 0x30
sr: [00:00.901031] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is enabled, OVP is disabled. Device is beeping.
sr: [00:00.901099] hwdriver: sr_config_get(): key 30043 (regulation) sdi 0x332819f0 cg NULL -> 'CC'
    regulation: CC (current)
sr: [00:00.980298] korad-kaxxxxp: Sleeping for processing 78969 usec
sr: [00:00.980352] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:00.980478] serial: Wrote 9/9 bytes.
sr: [00:00.981147] korad-kaxxxxp: want 1 bytes, timeout/retry: init 11/100, later 13/1.
sr: [00:00.981243] serial: Read 1/1 bytes.
sr: [00:00.981283] korad-kaxxxxp: got 1 bytes, received: '0'.
sr: [00:00.981394] korad-kaxxxxp: Status: 0x30
sr: [00:00.981452] korad-kaxxxxp: Status: CH1: constant current CH2: constant current. Tracking would be series and independent. Output is disabled. OCP is enabled, OVP is disabled. Device is beeping.
sr: [00:00.981529] hwdriver: sr_config_get(): key 30038 (ocp_enabled) sdi 0x332819f0 cg NULL -> true
    ocp_enabled: on (current), off
sr: [00:01.060637] korad-kaxxxxp: Sleeping for processing 78929 usec
sr: [00:01.060659] korad-kaxxxxp: Sending 'STATUS?'.
sr: [00:01.060695] serial: Wrote 9/9 bytes.
sr: [00:01.061053] korad-kaxxxxp: want 1 bytes, timeout/retry: init 11/100, later 13/1.
sr: [00:01.061102] serial: Read 1/1 bytes.
sr: [00:01.061114] korad-kaxxxxp: got 1 bytes, received: ''.
sr: [00:01.061127] korad-kaxxxxp: Status: 0x0a
sr: [00:01.061140] korad-kaxxxxp: Status: CH1: constant current CH2: constant voltage. Tracking would be series and tracking. Output is disabled. OCP is disabled, OVP is disabled. Device is silent.
sr: [00:01.061162] hwdriver: sr_config_get(): key 30035 (ovp_enabled) sdi 0x332819f0 cg NULL -> false
    ovp_enabled: on, off (current)
sr: [00:01.061182] device: korad-kaxxxxp: Closing device instance.
sr: [00:01.061195] serial: Closing serial port /dev/ttyUSB0.
sr: [00:01.074325] hwdriver: Cleaning up all drivers.

Setting values works, reading them back does not.

@cnf
Copy link

cnf commented May 28, 2025

bit further poking it, sending *IDN?\\n\r doesn't work, hell sending *IDN?\\n doesn't work!

Who the hell implemented this thing, and why did I end up with one? 😁

@MartinJM
Copy link
Author

MartinJM commented May 28, 2025

Who the hell implemented this thing, and why did I end up with one? 😁

Hahaha good questions :P

set add_newline to false in the discovery
sending *IDN?\n\r doesn't work

Hmmm I was hoping that either of these would work for your device, as then there would be overlap with my device as well.

I'm wondering if we can just send *IDN?, *IDN?\n, and *IDN?\\n in a row to always get an answer? I cannot test right now but will do so when I can.


Edit: So for my device it seems to be that it needs to start with *IDN? and then needs a newline some time after, but what comes in between does not matter. So this also only prints the identification output: *IDN?STATUS?\n.

@cnf
Copy link

cnf commented Sep 14, 2025

I don't know if you are still wanting to know @MartinJM ... it seems you just append 'n'

± tio VELLEMAN
[18:07:04.658] tio 3.9
[18:07:04.658] Press ctrl-t q to quit
[18:07:04.660] Connected to /dev/tty-CP2102
[18:07:04.661] Running script
*IDN?nQJE3005PV1.0
VSET1:10.000nVSET1?n10.00
ISET1:01.000nISET1?n0.000
ISET1:1.123nISET1?n1.123

no \n no /n no \\n .... just a single n...

@cnf
Copy link

cnf commented Sep 14, 2025

± sigrok-cli -d korad-kaxxxxp:conn=/dev/tty-CP2102 --scan
The following devices were found:
korad-kaxxxxp:conn=/dev/tty-CP2102 - Velleman LABPS3005DN with 2 channels: V I

I can SET values, and enable/disable the output, but sigrok-cli can't read them back it seems:

Set / Read
OptiNix home-manager/patches ± sigrok-cli -d korad-kaxxxxp:conn=/dev/tty-CP2102 --config voltage_target=07.000 --set
OptiNix home-manager/patches ± sigrok-cli -d korad-kaxxxxp:conn=/dev/tty-CP2102 --show
Driver functions:
    Power supply
Scan options:
    conn
    serialcomm
    force_detect
korad-kaxxxxp:conn=/dev/tty-CP2102 - Velleman LABPS3005DN with 2 channels: V I
Supported configuration options:
    conn: /dev/tty-CP2102 (current)
    continuous: on, off
    limit_samples: 0 (current)
    limit_time: 0 (current)
    voltage: 0.000000 (current)
    voltage_target: 0.000000 (current), 31.000000, 0.010000
    current: 0.000000 (current)
    current_limit: 0.000000 (current), 5.100000, 0.001000
    enabled: on, off (current)
    regulation: CC (current)
    ocp_enabled: on (current), off
    ovp_enabled: on, off (current)
OptiNix home-manager/patches ± sigrok-cli -d korad-kaxxxxp:conn=/dev/tty-CP2102 --config current_limit=0.123 --set
OptiNix home-manager/patches ± sigrok-cli -d korad-kaxxxxp:conn=/dev/tty-CP2102 --show
Driver functions:
    Power supply
Scan options:
    conn
    serialcomm
    force_detect
korad-kaxxxxp:conn=/dev/tty-CP2102 - Velleman LABPS3005DN with 2 channels: V I
Supported configuration options:
    conn: /dev/tty-CP2102 (current)
    continuous: on, off
    limit_samples: 0 (current)
    limit_time: 0 (current)
    voltage: 0.000000 (current)
    voltage_target: 0.000000 (current), 31.000000, 0.010000
    current: 0.000000 (current)
    current_limit: 0.000000 (current), 5.100000, 0.001000
    enabled: on, off (current)
    regulation: CC (current)
    ocp_enabled: on (current), off
    ovp_enabled: on, off (current)
OptiNix home-manager/patches ±  

@cnf
Copy link

cnf commented Sep 14, 2025

Yeah, so control works, but reading back doesn't. from smuview i can enable the output, but it doesn't see it is on, and the voltage readings jump all over the place...

@MartinJM
Copy link
Author

Hey, yeah always interested in stuff like this.

it seems you just append 'n'

And this is giving me a good laugh, so thank you for sharing. Is your device still fine if you send *IDN?n\n (with the \n being an actual newline of course)? That should be supported by my device as well, so if that works it might be a solution for the identification. Then after the identification we know which device it is so we can use exactly what the device requires.

Yeah, so control works, but reading back doesn't. from smuview i can enable the output, but it doesn't see it is on, and the voltage readings jump all over the place...

Hmmm that's too bad. Is this with just the n, or did you also try this with the \n?

@cnf
Copy link

cnf commented Sep 21, 2025

Hey, yeah always interested in stuff like this.

it seems you just append 'n'

And this is giving me a good laugh, so thank you for sharing. Is your device still fine if you send *IDN?n\n (with the \n being an actual newline of course)? That should be supported by my device as well, so if that works it might be a solution for the identification. Then after the identification we know which device it is so we can use exactly what the device requires.

Yep, it doesn't seem to care about the \n, you just send the normal commands, and then 1 or 0 characters, and then an n, if an \n follows, it doesn't seem to notice much.

Yeah, so control works, but reading back doesn't. from smuview i can enable the output, but it doesn't see it is on, and the voltage readings jump all over the place...

Hmmm that's too bad. Is this with just the n, or did you also try this with the \n?

either, if I run sigrok-cli -d korad-kaxxxxp:conn=/dev/tty-CP2102 --continuous it just gives me 0 on everything, except occastionally. I do not know why.

sigrok-cli -d korad-kaxxxxp:conn=/dev/tty-CP2102 --continuous
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
META ocp_enabled: 0
I: 0 mA DC
V: 0.00 V DC
META regulation: CC
META ocp_enabled: 1
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
I: 0 mA DC
V: 0.00 V DC
META regulation: CV
I: 0 mA DC
OptiNix ~ $ tio /dev/tty-CP2102 -b 9600 
[18:41:52.166] tio 3.9
[18:41:52.166] Press ctrl-t q to quit
[18:41:52.168] Connected to /dev/tty-CP2102
[18:41:57.683] Switched local echo on
*IDN?nQJE3005PV1.0
VSET1?n09.00
ISET1?n0.000
ISET1:0.123nISET1?n0.123

@abraxa
Copy link
Member

abraxa commented Nov 9, 2025

What's your take on this PR, @MartinJM? Should I merge it as-is or do you intend to make any changes to it?

That said, please only use /* ... */ for comments, not //

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants